home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / ghostview-1.5 / Path.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  16.6 KB  |  901 lines

  1. /*
  2.  * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Software Research Associates not be used
  9.  * in advertising or publicity pertaining to distribution of the software
  10.  * without specific, written prior permission.  Software Research Associates
  11.  * makes no representations about the suitability of this software for any
  12.  * purpose.  It is provided "as is" without express or implied warranty.
  13.  *
  14.  * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  15.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  16.  * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  18.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20.  * PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  * Author: Erik M. van der Poel
  23.  *         Software Research Associates, Inc., Tokyo, Japan
  24.  *         erik@sra.co.jp
  25.  */
  26.  
  27. #include <stdio.h>
  28.  
  29. #ifdef SEL_FILE_IGNORE_CASE
  30. #include <ctype.h>
  31. #endif /* def SEL_FILE_IGNORE_CASE */
  32.  
  33. #include <X11/Xos.h>
  34. #include <pwd.h>
  35. #include "SFinternal.h"
  36. #include "xstat.h"
  37. #include <X11/Xaw/Scrollbar.h>
  38.  
  39. #if defined(SVR4) || defined(SYSV) || defined(USG)
  40. extern uid_t getuid();
  41. extern void qsort();
  42. #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
  43.  
  44. typedef struct {
  45.     char    *name;
  46.     char    *dir;
  47. } SFLogin;
  48.  
  49. SFDir *SFdirs = NULL;
  50.  
  51. int SFdirEnd;
  52.  
  53. int SFdirPtr;
  54.  
  55. int SFbuttonPressed = 0;
  56.  
  57. static int SFdoNotTouchDirPtr = 0;
  58.  
  59. static int SFdoNotTouchVorigin = 0;
  60.  
  61. static SFDir SFrootDir, SFhomeDir;
  62.  
  63. static SFLogin *SFlogins;
  64.  
  65. static int SFtwiddle = 0;
  66.  
  67. int
  68. SFchdir(path)
  69.     char    *path;
  70. {
  71.     int    result;
  72.  
  73.     result = 0;
  74.  
  75.     if (strcmp(path, SFcurrentDir)) {
  76.         result = chdir(path);
  77.         if (!result) {
  78.             (void) strcpy(SFcurrentDir, path);
  79.         }
  80.     }
  81.  
  82.     return result;
  83. }
  84.  
  85. static
  86. SFfree(i)
  87.     int    i;
  88. {
  89.     register SFDir    *dir;
  90.     register int    j;
  91.  
  92.     dir = &(SFdirs[i]);
  93.  
  94.     for (j = dir->nEntries - 1; j >= 0; j--) {
  95.         if (dir->entries[j].shown != dir->entries[j].real) {
  96.             XtFree(dir->entries[j].shown);
  97.         }
  98.         XtFree(dir->entries[j].real);
  99.     }
  100.  
  101.     XtFree((char *) dir->entries);
  102.  
  103.     XtFree(dir->dir);
  104.  
  105.     dir->dir = NULL;
  106. }
  107.  
  108. static
  109. SFstrdup(s1, s2)
  110.     char    **s1;
  111.     char    *s2;
  112. {
  113.     *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
  114. }
  115.  
  116. static
  117. SFunreadableDir(dir)
  118.     SFDir    *dir;
  119. {
  120.     char    *cannotOpen = "<cannot open> ";
  121.  
  122.     dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
  123.     dir->entries[0].statDone = 1;
  124.     SFstrdup(&dir->entries[0].real, cannotOpen);
  125.     dir->entries[0].shown = dir->entries[0].real;
  126.     dir->nEntries = 1;
  127.     dir->nChars = strlen(cannotOpen);
  128. }
  129.  
  130. #ifdef SEL_FILE_IGNORE_CASE
  131. static
  132. SFstrncmp(p, q, n)
  133.     register char    *p, *q;
  134.     register int    n;
  135. {
  136.     register char    c1, c2;
  137.     char        *psave, *qsave;
  138.     int        nsave;
  139.  
  140.     psave = p;
  141.     qsave = q;
  142.     nsave = n;
  143.  
  144.     c1 = *p++;
  145.     if (islower(c1)) {
  146.         c1 = toupper(c1);
  147.     }
  148.     c2 = *q++;
  149.     if (islower(c2)) {
  150.         c2 = toupper(c2);
  151.     }
  152.  
  153.     while ((--n >= 0) && (c1 == c2)) {
  154.         if (!c1) {
  155.             return strncmp(psave, qsave, nsave);
  156.         }
  157.         c1 = *p++;
  158.         if (islower(c1)) {
  159.             c1 = toupper(c1);
  160.         }
  161.         c2 = *q++;
  162.         if (islower(c2)) {
  163.             c2 = toupper(c2);
  164.         }
  165.     }
  166.  
  167.     if (n < 0) {
  168.         return strncmp(psave, qsave, nsave);
  169.     }
  170.  
  171.     return c1 - c2;
  172. }
  173. #endif /* def SEL_FILE_IGNORE_CASE */
  174.  
  175. static
  176. SFreplaceText(dir, str)
  177.     SFDir    *dir;
  178.     char    *str;
  179. {
  180.     int    len;
  181.  
  182.     *(dir->path) = 0;
  183.     len = strlen(str);
  184.     if (str[len - 1] == '/') {
  185.         (void) strcat(SFcurrentPath, str);
  186.     } else {
  187.         (void) strncat(SFcurrentPath, str, len - 1);
  188.     }
  189.     if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
  190.         SFsetText(SFcurrentPath);
  191.     } else {
  192.         SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  193.     }
  194.  
  195.     SFtextChanged();
  196. }
  197.  
  198. static void
  199. SFexpand(str)
  200.     char    *str;
  201. {
  202.     int    len;
  203.     int    cmp;
  204.     char    *name, *growing;
  205.     SFDir    *dir;
  206.     SFEntry    *entry, *max;
  207.  
  208.     len = strlen(str);
  209.  
  210.     dir = &(SFdirs[SFdirEnd - 1]);
  211.  
  212.     if (dir->beginSelection == -1) {
  213.         SFstrdup(&str, str);
  214.         SFreplaceText(dir, str);
  215.         XtFree(str);
  216.         return;
  217.     } else if (dir->beginSelection == dir->endSelection) {
  218.         SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
  219.         return;
  220.     }
  221.  
  222.     max = &(dir->entries[dir->endSelection + 1]);
  223.  
  224.     name = dir->entries[dir->beginSelection].shown;
  225.     SFstrdup(&growing, name);
  226.  
  227.     cmp = 0;
  228.     while (!cmp) {
  229.         entry = &(dir->entries[dir->beginSelection]);
  230.         while (entry < max) {
  231.             if (cmp = strncmp(growing, entry->shown, len)) {
  232.                 break;
  233.             }
  234.             entry++;
  235.         }
  236.         len++;
  237.     }
  238.  
  239.     /*
  240.      * SFreplaceText() expects filename
  241.      */
  242.     growing[len - 2] = ' ';
  243.  
  244.     growing[len - 1] = 0;
  245.     SFreplaceText(dir, growing);
  246.     XtFree(growing);
  247. }
  248.  
  249. static int
  250. SFfindFile(dir, str)
  251.     SFDir        *dir;
  252.     register char    *str;
  253. {
  254.     register int    i, last, max;
  255.     register char    *name, save;
  256.     SFEntry        *entries;
  257.     int        len;
  258.     int        begin, end;
  259.     int        result;
  260.  
  261.     len = strlen(str);
  262.  
  263.     if (str[len - 1] == ' ') {
  264.         SFexpand(str);
  265.         return 1;
  266.     } else if (str[len - 1] == '/') {
  267.         len--;
  268.     }
  269.  
  270.     max = dir->nEntries;
  271.  
  272.     entries = dir->entries;
  273.  
  274.     i = 0;
  275.     while (i < max) {
  276.         name = entries[i].shown;
  277.         last = strlen(name) - 1;
  278.         save = name[last];
  279.         name[last] = 0;
  280.  
  281. #ifdef SEL_FILE_IGNORE_CASE
  282.         result = SFstrncmp(str, name, len);
  283. #else /* def SEL_FILE_IGNORE_CASE */
  284.         result = strncmp(str, name, len);
  285. #endif /* def SEL_FILE_IGNORE_CASE */
  286.  
  287.         name[last] = save;
  288.         if (result <= 0) {
  289.             break;
  290.         }
  291.         i++;
  292.     }
  293.     begin = i;
  294.     while (i < max) {
  295.         name = entries[i].shown;
  296.         last = strlen(name) - 1;
  297.         save = name[last];
  298.         name[last] = 0;
  299.  
  300. #ifdef SEL_FILE_IGNORE_CASE
  301.         result = SFstrncmp(str, name, len);
  302. #else /* def SEL_FILE_IGNORE_CASE */
  303.         result = strncmp(str, name, len);
  304. #endif /* def SEL_FILE_IGNORE_CASE */
  305.  
  306.         name[last] = save;
  307.         if (result) {
  308.             break;
  309.         }
  310.         i++;
  311.     }
  312.     end = i;
  313.  
  314.     if (begin != end) {
  315.         if (
  316.             (dir->beginSelection != begin) ||
  317.             (dir->endSelection != end - 1)
  318.         ) {
  319.             dir->changed = 1;
  320.             dir->beginSelection = begin;
  321.             if (str[strlen(str) - 1] == '/') {
  322.                 dir->endSelection = begin;
  323.             } else {
  324.                 dir->endSelection = end - 1;
  325.             }
  326.         }
  327.     } else {
  328.         if (dir->beginSelection != -1) {
  329.             dir->changed = 1;
  330.             dir->beginSelection = -1;
  331.             dir->endSelection = -1;
  332.         }
  333.     }
  334.  
  335.     if (
  336.         SFdoNotTouchVorigin ||
  337.         ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
  338.     ) {
  339.         SFdoNotTouchVorigin = 0;
  340.         return 0;
  341.     }
  342.  
  343.     i = begin - 1;
  344.     if (i > max - SFlistSize) {
  345.         i = max - SFlistSize;
  346.     }
  347.     if (i < 0) {
  348.         i = 0;
  349.     }
  350.  
  351.     if (dir->vOrigin != i) {
  352.         dir->vOrigin = i;
  353.         dir->changed = 1;
  354.     }
  355.  
  356.     return 0;
  357. }
  358.  
  359. static
  360. SFunselect()
  361. {
  362.     SFDir    *dir;
  363.  
  364.     dir = &(SFdirs[SFdirEnd - 1]);
  365.     if (dir->beginSelection != -1) {
  366.         dir->changed = 1;
  367.     }
  368.     dir->beginSelection = -1;
  369.     dir->endSelection = -1;
  370. }
  371.  
  372. static int
  373. SFcompareLogins(p, q)
  374.     SFLogin    *p, *q;
  375. {
  376.     return strcmp(p->name, q->name);
  377. }
  378.  
  379. static
  380. SFgetHomeDirs()
  381. {
  382.     struct passwd    *pw;
  383.     int        alloc;
  384.     int        i;
  385.     SFEntry        *entries = NULL;
  386.     int        len;
  387.     int        maxChars;
  388.  
  389.     {
  390.             alloc = 1;
  391.             i = 1;
  392.             entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
  393.             SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
  394.             entries[0].real = XtMalloc(3);
  395.             (void) strcpy(entries[0].real, "~");
  396.             entries[0].shown = entries[0].real;
  397.             entries[0].statDone = 1;
  398.             SFlogins[0].name = "";
  399.             pw = getpwuid((int) getuid());
  400.             SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
  401.             maxChars = 0;
  402.     }
  403.  
  404.     (void) setpwent();
  405.  
  406.     while ((pw = getpwent()) && (*(pw->pw_name))) {
  407.             if (i >= alloc) {
  408.                 alloc *= 2;
  409.                 entries = (SFEntry *) XtRealloc(
  410.                     (char *) entries,
  411.                     (unsigned) (alloc * sizeof(SFEntry))
  412.                 );
  413.                 SFlogins = (SFLogin *) XtRealloc(
  414.                     (char *) SFlogins,
  415.                     (unsigned) (alloc * sizeof(SFLogin))
  416.                 );
  417.             }
  418.             len = strlen(pw->pw_name);
  419.             entries[i].real = XtMalloc((unsigned) (len + 3));
  420.             (void) strcat(strcpy(entries[i].real, "~"),
  421.                 pw->pw_name);
  422.             entries[i].shown = entries[i].real;
  423.             entries[i].statDone = 1;
  424.             if (len > maxChars) {
  425.                 maxChars = len;
  426.             }
  427.             SFstrdup(&SFlogins[i].name, pw->pw_name);
  428.             SFstrdup(&SFlogins[i].dir, pw->pw_dir);
  429.             i++;
  430.     }
  431.  
  432.     SFhomeDir.dir            = XtMalloc(1)    ;
  433.     SFhomeDir.dir[0]        = 0        ;
  434.     SFhomeDir.path            = SFcurrentPath    ;
  435.     SFhomeDir.entries        = entries    ;
  436.     SFhomeDir.nEntries        = i        ;
  437.     SFhomeDir.vOrigin        = 0        ;    /* :-) */
  438.     SFhomeDir.nChars        = maxChars + 2    ;
  439.     SFhomeDir.hOrigin        = 0        ;
  440.     SFhomeDir.changed        = 1        ;
  441.     SFhomeDir.beginSelection    = -1        ;
  442.     SFhomeDir.endSelection        = -1        ;
  443.  
  444. #if defined(SVR4) || defined(SYSV) || defined(USG)
  445.     qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
  446.     qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
  447. #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
  448.     qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
  449.     qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
  450. #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
  451.  
  452.     for (i--; i >= 0; i--) {
  453.         (void) strcat(entries[i].real, "/");
  454.     }
  455. }
  456.  
  457. static int
  458. SFfindHomeDir(begin, end)
  459.     char    *begin, *end;
  460. {
  461.     char    save;
  462.     char    *theRest;
  463.     int    i;
  464.  
  465.     save = *end;
  466.     *end = 0;
  467.  
  468.     for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
  469.         if (!strcmp(SFhomeDir.entries[i].real, begin)) {
  470.             *end = save;
  471.             SFstrdup(&theRest, end);
  472.             (void) strcat(strcat(strcpy(SFcurrentPath,
  473.                 SFlogins[i].dir), "/"), theRest);
  474.             XtFree(theRest);
  475.             SFsetText(SFcurrentPath);
  476.             SFtextChanged();
  477.             return 1;
  478.         }
  479.     }
  480.  
  481.     *end = save;
  482.  
  483.     return 0;
  484. }
  485.  
  486. SFupdatePath()
  487. {
  488.     static int    alloc;
  489.     static int    wasTwiddle = 0;
  490.     char        *begin, *end;
  491.     int        i, j;
  492.     int        prevChange;
  493.     int        SFdirPtrSave, SFdirEndSave;
  494.     SFDir        *dir;
  495.  
  496.     if (!SFdirs) {
  497.         SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
  498.         dir = &(SFdirs[0]);
  499.         SFstrdup(&dir->dir, "/");
  500.         (void) SFchdir("/");
  501.         (void) SFgetDir(dir);
  502.         for (j = 1; j < alloc; j++) {
  503.             SFdirs[j].dir = NULL;
  504.         }
  505.         dir->path = SFcurrentPath + 1;
  506.         dir->vOrigin = 0;
  507.         dir->hOrigin = 0;
  508.         dir->changed = 1;
  509.         dir->beginSelection = -1;
  510.         dir->endSelection = -1;
  511.         SFhomeDir.dir = NULL;
  512.     }
  513.  
  514.     SFdirEndSave = SFdirEnd;
  515.     SFdirEnd = 1;
  516.  
  517.     SFdirPtrSave = SFdirPtr;
  518.     SFdirPtr = 0;
  519.  
  520.     begin = NULL;
  521.  
  522.     if (SFcurrentPath[0] == '~') {
  523.         if (!SFtwiddle) {
  524.             SFtwiddle = 1;
  525.             dir = &(SFdirs[0]);
  526.             SFrootDir = *dir;
  527.             if (!SFhomeDir.dir) {
  528.                 SFgetHomeDirs();
  529.             }
  530.             *dir = SFhomeDir;
  531.             dir->changed = 1;
  532.         }
  533.         end = SFcurrentPath;
  534.         SFdoNotTouchDirPtr = 1;
  535.         wasTwiddle = 1;
  536.     } else {
  537.         if (SFtwiddle) {
  538.             SFtwiddle = 0;
  539.             dir = &(SFdirs[0]);
  540.             *dir = SFrootDir;
  541.             dir->changed = 1;
  542.         }
  543.         end = SFcurrentPath + 1;
  544.     }
  545.  
  546.     i = 0;
  547.  
  548.     prevChange = 0;
  549.  
  550.     while (*end) {
  551.         while (*end++ == '/') {
  552.             ;
  553.         }
  554.         end--;
  555.         begin = end;
  556.         while ((*end) && (*end++ != '/')) {
  557.             ;
  558.         }
  559.         if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
  560.             SFdirPtr = i - 1;
  561.             if (SFdirPtr < 0) {
  562.                 SFdirPtr = 0;
  563.             }
  564.         }
  565.         if (*begin) {
  566.             if (*(end - 1) == '/') {
  567.                 char save = *end;
  568.  
  569.                 if (SFtwiddle) {
  570.                     if (SFfindHomeDir(begin, end)) {
  571.                         return;
  572.                     }
  573.                 }
  574.                 *end = 0;
  575.                 i++;
  576.                 SFdirEnd++;
  577.                 if (i >= alloc) {
  578.                     SFdirs = (SFDir *) XtRealloc(
  579.                         (char *) SFdirs,
  580.                         (unsigned) ((alloc *= 2) *
  581.                             sizeof(SFDir))
  582.                     );
  583.                     for (j = alloc / 2; j < alloc; j++) {
  584.                         SFdirs[j].dir = NULL;
  585.                     }
  586.                 }
  587.                 dir = &(SFdirs[i]);
  588.                 if (
  589.                     (!(dir->dir)) ||
  590.                     prevChange ||
  591.                     strcmp(dir->dir, begin)
  592.                 ) {
  593.                     if (dir->dir) {
  594.                         SFfree(i);
  595.                     }
  596.                     prevChange = 1;
  597.                     SFstrdup(&dir->dir, begin);
  598.                     dir->path = end;
  599.                     dir->vOrigin = 0;
  600.                     dir->hOrigin = 0;
  601.                     dir->changed = 1;
  602.                     dir->beginSelection = -1;
  603.                     dir->endSelection = -1;
  604.                     (void) SFfindFile(dir - 1, begin);
  605.                     if (
  606.                         SFchdir(SFcurrentPath) ||
  607.                         SFgetDir(dir)
  608.                     ) {
  609.                         SFunreadableDir(dir);
  610.                         break;
  611.                     }
  612.                 }
  613.                 *end = save;
  614.                 if (!save) {
  615.                     SFunselect();
  616.                 }
  617.             } else {
  618.                 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
  619.                     return;
  620.                 }
  621.             }
  622.         } else {
  623.             SFunselect();
  624.         }
  625.     }
  626.  
  627.     if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
  628.         SFunselect();
  629.     }
  630.  
  631.     for (i = SFdirEnd; i < alloc; i++) {
  632.         if (SFdirs[i].dir) {
  633.             SFfree(i);
  634.         }
  635.     }
  636.  
  637.     if (SFdoNotTouchDirPtr) {
  638.         if (wasTwiddle) {
  639.             wasTwiddle = 0;
  640.             SFdirPtr = SFdirEnd - 2;
  641.             if (SFdirPtr < 0) {
  642.                 SFdirPtr = 0;
  643.             }
  644.         } else {
  645.             SFdirPtr = SFdirPtrSave;
  646.         }
  647.         SFdoNotTouchDirPtr = 0;
  648.     }
  649.  
  650.     if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
  651.         XawScrollbarSetThumb(
  652.             selFileHScroll,
  653.             (float) (((double) SFdirPtr) / SFdirEnd),
  654.             (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
  655.                 SFdirEnd)
  656.         );
  657.     }
  658.  
  659.     if (SFdirPtr != SFdirPtrSave) {
  660.         SFdrawLists(SF_DO_SCROLL);
  661.     } else {
  662.         for (i = 0; i < 3; i++) {
  663.             if (SFdirPtr + i < SFdirEnd) {
  664.                 if (SFdirs[SFdirPtr + i].changed) {
  665.                     SFdirs[SFdirPtr + i].changed = 0;
  666.                     SFdrawList(i, SF_DO_SCROLL);
  667.                 }
  668.             } else {
  669.                 SFclearList(i, SF_DO_SCROLL);
  670.             }
  671.         }
  672.     }
  673. }
  674.  
  675. SFsetText(path)
  676.     char    *path;
  677. {
  678.     XawTextBlock    text;
  679.  
  680.     text.firstPos = 0;
  681.     text.length = strlen(path);
  682.     text.ptr = path;
  683.     text.format = FMT8BIT;
  684.  
  685.     XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
  686.     XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
  687. }
  688.  
  689. /* ARGSUSED */
  690. void
  691. SFbuttonPressList(w, n, event)
  692.     Widget            w;
  693.     int            n;
  694.     XButtonPressedEvent    *event;
  695. {
  696.     SFbuttonPressed = 1;
  697. }
  698.  
  699. /* ARGSUSED */
  700. void
  701. SFbuttonReleaseList(w, n, event)
  702.     Widget            w;
  703.     int            n;
  704.     XButtonReleasedEvent    *event;
  705. {
  706.     SFDir    *dir;
  707.  
  708.     SFbuttonPressed = 0;
  709.  
  710.     if (SFcurrentInvert[n] != -1) {
  711.         if (n < 2) {
  712.             SFdoNotTouchDirPtr = 1;
  713.         }
  714.         SFdoNotTouchVorigin = 1;
  715.         dir = &(SFdirs[SFdirPtr + n]);
  716.         SFreplaceText(
  717.             dir,
  718.             dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
  719.         );
  720.         SFmotionList(w, n, event);
  721.     }
  722. }
  723.  
  724. static int
  725. SFcheckDir(n, dir)
  726.     int        n;
  727.     SFDir        *dir;
  728. {
  729.     struct stat    statBuf;
  730.     int        i;
  731.  
  732.     if (
  733.         (!stat(".", &statBuf)) &&
  734.         (statBuf.st_mtime != dir->mtime)
  735.     ) {
  736.  
  737.         /*
  738.          * If the pointer is currently in the window that we are about
  739.          * to update, we must warp it to prevent the user from
  740.          * accidentally selecting the wrong file.
  741.          */
  742.         if (SFcurrentInvert[n] != -1) {
  743.             XWarpPointer(
  744.                 SFdisplay,
  745.                 None,
  746.                 XtWindow(selFileLists[n]),
  747.                 0,
  748.                 0,
  749.                 0,
  750.                 0,
  751.                 0,
  752.                 0
  753.             );
  754.         }
  755.  
  756.         for (i = dir->nEntries - 1; i >= 0; i--) {
  757.             if (dir->entries[i].shown != dir->entries[i].real) {
  758.                 XtFree(dir->entries[i].shown);
  759.             }
  760.             XtFree(dir->entries[i].real);
  761.         }
  762.         XtFree((char *) dir->entries);
  763.         if (SFgetDir(dir)) {
  764.             SFunreadableDir(dir);
  765.         }
  766.         if (dir->vOrigin > dir->nEntries - SFlistSize) {
  767.             dir->vOrigin = dir->nEntries - SFlistSize;
  768.         }
  769.         if (dir->vOrigin < 0) {
  770.             dir->vOrigin = 0;
  771.         }
  772.         if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
  773.             dir->hOrigin = dir->nChars - SFcharsPerEntry;
  774.         }
  775.         if (dir->hOrigin < 0) {
  776.             dir->hOrigin = 0;
  777.         }
  778.         dir->beginSelection = -1;
  779.         dir->endSelection = -1;
  780.         SFdoNotTouchVorigin = 1;
  781.         if ((dir + 1)->dir) {
  782.             (void) SFfindFile(dir, (dir + 1)->dir);
  783.         } else {
  784.             (void) SFfindFile(dir, dir->path);
  785.         }
  786.  
  787.         if (!SFworkProcAdded) {
  788.             (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
  789.             SFworkProcAdded = 1;
  790.         }
  791.  
  792.         return 1;
  793.     }
  794.  
  795.     return 0;
  796. }
  797.  
  798. static int
  799. SFcheckFiles(dir)
  800.     SFDir    *dir;
  801. {
  802.     int        from, to;
  803.     int        result;
  804.     char        old, new;
  805.     int        i;
  806.     char        *str;
  807.     int        last;
  808.     struct stat    statBuf;
  809.  
  810.     result = 0;
  811.  
  812.     from = dir->vOrigin;
  813.     to = dir->vOrigin + SFlistSize;
  814.     if (to > dir->nEntries) {
  815.         to = dir->nEntries;
  816.     }
  817.  
  818.     for (i = from; i < to; i++) {
  819.         str = dir->entries[i].real;
  820.         last = strlen(str) - 1;
  821.         old = str[last];
  822.         str[last] = 0;
  823.         if (stat(str, &statBuf)) {
  824.             new = ' ';
  825.         } else {
  826.             new = SFstatChar(&statBuf);
  827.         }
  828.         str[last] = new;
  829.         if (new != old) {
  830.             result = 1;
  831.         }
  832.     }
  833.  
  834.     return result;
  835. }
  836.  
  837. void
  838. SFdirModTimer(cl, id)
  839.         XtPointer       cl;
  840.         XtIntervalId    *id;
  841. {
  842.     static int    n = -1;
  843.     static int    f = 0;
  844.     char        save;
  845.     SFDir        *dir;
  846.  
  847.     if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
  848.         n++;
  849.         if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {
  850.             n = 0;
  851.             f++;
  852.             if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {
  853.                 f = 0;
  854.             }
  855.         }
  856.         dir = &(SFdirs[SFdirPtr + n]);
  857.         save = *(dir->path);
  858.         *(dir->path) = 0;
  859.         if (SFchdir(SFcurrentPath)) {
  860.             *(dir->path) = save;
  861.  
  862.             /*
  863.              * force a re-read
  864.              */
  865.             *(dir->dir) = 0;
  866.  
  867.             SFupdatePath();
  868.         } else {
  869.             *(dir->path) = save;
  870.             if (
  871.                 SFcheckDir(n, dir) ||
  872.                 ((f == n) && SFcheckFiles(dir))
  873.             ) {
  874.                 SFdrawList(n, SF_DO_SCROLL);
  875.             }
  876.         }
  877.     }
  878.  
  879.     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
  880.         SFdirModTimer, (XtPointer) NULL);
  881. }
  882.  
  883. /* Return a single character describing what kind of file STATBUF is.  */
  884.  
  885. char
  886. SFstatChar (statBuf)
  887.     struct stat *statBuf;
  888. {
  889.     if (S_ISDIR (statBuf->st_mode)) {
  890.         return '/';
  891.     } else if (S_ISREG (statBuf->st_mode)) {
  892.       return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
  893. #ifdef S_ISSOCK
  894.     } else if (S_ISSOCK (statBuf->st_mode)) {
  895.         return '=';
  896. #endif /* S_ISSOCK */
  897.     } else {
  898.         return ' ';
  899.     }
  900. }
  901.